/*
 *  Copyright 2011 Iurii Dunko, Iana Potochniak.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package org.opu.yyminijava.visitor;

import java.util.ArrayList;
import java.util.List;
import org.opu.yyminijava.syntaxtree.*;
import org.opu.yyminijava.syntaxtree.primary.*;

/**
 *
 * @author Iurii Dunko
 * @author Iana  Potochniak
 */
public class Visitor {

    private List<VisitorHandler> handlers;

    public Visitor() {
        this(new ArrayList<VisitorHandler>());
    }

    public Visitor(List<VisitorHandler> handlers) {
        this.handlers = handlers;
    }

    public void addHandler(VisitorHandler handler) {
        handlers.add(handler);
    }

    public void visit(ArgumentList rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ArithmeticalAddExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ArithmeticalAddOp rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ArithmeticalMullExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ArithmeticalMullOp rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ArrayAccess rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ArrayCreationExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ArrayType rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Block rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(BooleanExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(BooleanLiteral rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(BooleanOp rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(BreakStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(CallSuper rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(CharLiteral rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ClassBody rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ClassDeclaration rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ClassInstanceCreationExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ClassMemberDeclaration rule) {
        if (rule instanceof FieldDeclaration){
            visit((FieldDeclaration) rule);
        } else if(rule instanceof MethodDeclaration){
            visit((MethodDeclaration) rule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal class member " + rule);
        }
    }

    public void visit(ClassType rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(CompareExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(CompareOp rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(CompilationUnit rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ContinueStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(CreationExpression rule) {
        if (rule instanceof ArrayCreationExpression){
            visit((ArrayCreationExpression) rule);
        } else if(rule instanceof ClassInstanceCreationExpression){
            visit((ClassInstanceCreationExpression) rule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal candidat for creation " + rule);
        }
    }

    public void visit(DoWhileStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ElseStatementPart rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Expression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(FieldDeclaration rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(FieldInvocation rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ForInitExpressionPart notRule) {
        if (notRule instanceof LocalVariableDeclaration){
            visit((LocalVariableDeclaration) notRule);
        } else if(notRule instanceof StatementExpressionList){
            visit((StatementExpressionList) notRule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal expression part " + notRule);
        }
    }

    public void visit(ForInit rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(FormalParameter rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(FormalParameterList rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ForStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ForUpdate rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Goal rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(IdentifierList rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(IfElseStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(IfStatementPart rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(IntegerLiteral rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Literal rule) {
        if (rule instanceof BooleanLiteral){
            visit((BooleanLiteral)rule);
        } else if (rule instanceof CharLiteral){
            visit((CharLiteral)rule);
        } else if (rule instanceof IntegerLiteral){
            visit((IntegerLiteral)rule);
        } else if (rule instanceof NullLiteral){
            visit((NullLiteral)rule);
        } else if (rule instanceof StringLiteral){
            visit((StringLiteral)rule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal literal type " + rule);
        }
    }

    public void visit(LocalVariableDeclaration rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(LocalVariableDeclarationStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(LogicalExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(LogicalOp rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(MethodBody rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(MethodCall rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(MethodCallStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(MethodDeclaration rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(MethodDeclarator rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(MethodHeader rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(MethodInvocation rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Modifier rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Modifiers rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Name rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(NewInstance rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(NullLiteral rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PostfixExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PrefixExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PrefixOp rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PrimitiveType rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(ReferenceType rule) {
        if (rule instanceof ArrayType){
            visit((ArrayType)rule);
        } else if (rule instanceof ClassType){
            visit((ClassType)rule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal reference type " + rule);
        }
    }

    public void visit(ReturnStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(StatementEmpty rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(StatementExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(StatementExpressionList rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Statement rule) {
        if (rule instanceof LocalVariableDeclarationStatement){
            visit((LocalVariableDeclarationStatement)rule);
        } else if (rule instanceof Block){
            visit((Block)rule);
        } else if (rule instanceof MethodCallStatement){
            visit((MethodCallStatement)rule);
        } else if (rule instanceof IfElseStatement){
            visit((IfElseStatement)rule);
        } else if (rule instanceof WhileStatement){
            visit((WhileStatement)rule);
        } else if (rule instanceof DoWhileStatement){
            visit((DoWhileStatement)rule);
        } else if (rule instanceof ReturnStatement){
            visit((ReturnStatement)rule);
        } else if (rule instanceof BreakStatement){
            visit((BreakStatement)rule);
        } else if (rule instanceof ContinueStatement){
            visit((ContinueStatement)rule);
        } else if (rule instanceof ForStatement){
            visit((ForStatement)rule);
        } else if (rule instanceof StatementEmpty){
            visit((StatementEmpty)rule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal statement " + rule);
        }
    }

    public void visit(StringLiteral rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Suffix rule) {
        if (rule instanceof ArrayAccess){
            visit((ArrayAccess)rule);
        } else if (rule instanceof FieldInvocation){
            visit((FieldInvocation)rule);
        } else if (rule instanceof MethodInvocation){
            visit((MethodInvocation)rule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal suffix " + rule);
        }
    }

    public void visit(TypeDeclaration rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Type rule) {
        if (rule instanceof ArrayType){
            visit((ArrayType)rule);
        } else if (rule instanceof ClassType){
            visit((ClassType)rule);
        } else if (rule instanceof PrimitiveType){
            visit((PrimitiveType)rule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal type " + rule);
        }
    }

    public void visit(VariableDeclarator rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(VariableDeclarators rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(WhileStatement rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PrimaryFromExpression rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PrimaryFromIdentifier rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PrimaryFromLiteral rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PrimaryFromNewInstance rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(PrimaryFromThis rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }

    public void visit(Primary rule) {
        if (rule instanceof PrimaryFromExpression){
            visit((PrimaryFromExpression)rule);
        } else if (rule instanceof PrimaryFromIdentifier){
            visit((PrimaryFromIdentifier)rule);
        } else if (rule instanceof PrimaryFromLiteral){
            visit((PrimaryFromLiteral)rule);
        } else if (rule instanceof PrimaryFromNewInstance){
            visit((PrimaryFromNewInstance)rule);
        } else if (rule instanceof PrimaryFromThis){
            visit((PrimaryFromThis)rule);
        } else if (rule instanceof PrimaryMethodCall){
            visit((PrimaryMethodCall)rule);
        } else {
            // TODO: create own exception struction!
            // Using error is temporary solution, we use exception when the
            // incoming file contains errors, when the problem in our compiler
            // we use errors (but it for now)
            throw new Error("Illegal primary " + rule);
        }
    }

    public void visit(PrimaryMethodCall rule) {
        for (VisitorHandler handler : handlers) {
            handler.onVisitStart(rule, false);
        }

        rule.accept(this);

        for (VisitorHandler handler : handlers) {
            handler.onVisitEnd(rule, false);
        }
    }
}
